package com.jctrip.hotel.management.service;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jctrip.hotel.common.util.BeanUtil;
import com.jctrip.hotel.common.util.RandomUtil;
import com.jctrip.hotel.domain.dao.HtOrderRouteRecordDao;
import com.jctrip.hotel.domain.dao.MgPerminssionDao;
import com.jctrip.hotel.domain.dao.MgUserInfoDao;
import com.jctrip.hotel.domain.dao.MgUserPermissionDao;
import com.jctrip.hotel.domain.entity.HtOrderRouteRecord;
import com.jctrip.hotel.domain.entity.MgPerminssion;
import com.jctrip.hotel.domain.entity.MgUserInfo;
import com.jctrip.hotel.domain.entity.MgUserPermission;
import com.jctrip.hotel.management.model.param.*;
import com.jctrip.hotel.management.model.result.*;
import com.jctrip.hotel.management.util.JwtUtil;
import com.jctrip.hotel.management.util.MD5Util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SystemService {

    @Autowired
    private MgUserInfoDao mgUserInfoDao;

    @Autowired
    private MgPerminssionDao mgPerminssionDao;

    @Autowired
    private MgUserPermissionDao mgUserPermissionDao;

    @Autowired
    private HtOrderRouteRecordDao htOrderRouteRecordDao;

    public LoginResult userLogin(LoginParam param, HttpServletRequest request) {
        if (StringUtils.isBlank(param.getUsername())) {
            throw new RuntimeException("账户为空");
        }
        if (StringUtils.isBlank(param.getPassword())) {
            throw new RuntimeException("密码为空");
        }
        MgUserInfo mgUserInfo = mgUserInfoDao.selectOne(new LambdaQueryWrapper<MgUserInfo>()
                .eq(MgUserInfo::getUsername, param.getUsername())
                .eq(MgUserInfo::getDelFlag, 0));
        if (null == mgUserInfo) {
            throw new RuntimeException("账户不存在");
        }
        String salt = Optional.ofNullable(mgUserInfo.getSalt()).orElse("");
        String password = MD5Util.encode(param.getPassword(), salt);

        if(!mgUserInfo.getPassword().equals(password)){
            throw new RuntimeException("密码不正确");
        }
        if(mgUserPermissionDao.selectOne(new LambdaQueryWrapper<MgUserPermission>()
                .eq(MgUserPermission::getUsername, mgUserInfo.getId())
                .eq(MgUserPermission::getPermissionUrl, "/dashboard")) == null){
            throw new RuntimeException("用户未有权限");
        }
        //修改用户登录时间 和 ip 地址
        mgUserInfoDao.update(mgUserInfo, new LambdaUpdateWrapper<MgUserInfo>()
                .set(MgUserInfo::getLastLoginTime, new Date())
                .set(MgUserInfo::getLastLoginIp, getIpAdrress(request))
                .eq(MgUserInfo::getUsername, mgUserInfo.getUsername()));

        return LoginResult.builder()
                .permissionUrls(getPermission(String.valueOf(mgUserInfo.getId())))
                .username(mgUserInfo.getUsername())
                .realName(mgUserInfo.getRealname())
                .token(JwtUtil.createJwt(String.valueOf(mgUserInfo.getId()), mgUserInfo.getUsername(), new HashMap<>())).build();
    }

    public GetUserResult user(HttpServletRequest request){
        String token = request.getHeader("token");
        if(StringUtils.isBlank(token)){
            throw new RuntimeException("请先登录!");
        }
        String userName = JwtUtil.parseJwt(token).getSubject();
        MgUserInfo mgUserInfo = mgUserInfoDao.selectOne(new LambdaQueryWrapper<MgUserInfo>()
                .eq(MgUserInfo::getUsername, userName));
        if(null == mgUserInfo){
            throw new RuntimeException("用户不存在");
        }
        return GetUserResult.builder()
                .avatar(mgUserInfo.getAvatar())
                .permissionUrls(getPermission(String.valueOf(mgUserInfo.getId())))
                .realName(mgUserInfo.getRealname())
                .username(mgUserInfo.getUsername())
                .build();
    }

    public GetHomepageResult homepage(HttpServletRequest request){
        String token = request.getHeader("token");
        if(StringUtils.isBlank(token)){
            throw new RuntimeException("请先登录!");
        }
        String userName = JwtUtil.parseJwt(token).getSubject();
        MgUserInfo mgUserInfo = mgUserInfoDao.selectOne(new LambdaQueryWrapper<MgUserInfo>()
                .eq(MgUserInfo::getUsername, userName));
        if(null == mgUserInfo){
            throw new RuntimeException("用户不存在");
        }
        QueryWrapper<HtOrderRouteRecord> queryWrapper = new QueryWrapper<>();
        Date total = new Date();
        Date yesterday = DateUtils.addDays(total, -1);
        queryWrapper.select("sum(room_count * DATEDIFF(depart_date,arrive_date)) as id,sum(payment_price) as payment_price")
                .in("route_order_status", 20, 50)
                .between("create_time", DateUtil.beginOfDay(total), DateUtil.endOfDay(total));
        HtOrderRouteRecord htOrderRouteRecord = htOrderRouteRecordDao.selectOne(queryWrapper);

        QueryWrapper<HtOrderRouteRecord> yesterdayQueryWrapper = new QueryWrapper<>();
        yesterdayQueryWrapper.select("sum(payment_price) as payment_price")
                .in("route_order_status", 20, 50)
                .between("create_time", DateUtil.beginOfDay(yesterday), DateUtil.endOfDay(yesterday));
        HtOrderRouteRecord yesterdayHtOrderRouteRecord = htOrderRouteRecordDao.selectOne(yesterdayQueryWrapper);
        return GetHomepageResult.builder()
                .avatar(mgUserInfo.getAvatar())
                .lastLoginTime(mgUserInfo.getLastLoginTime())
                .realName(mgUserInfo.getRealname())
                .useDay(DateUtil.betweenDay(mgUserInfo.getCreateTime(), new Date(), true) + 1)
                .totalRMNight(htOrderRouteRecord.getId())
                .totalSalesToday(htOrderRouteRecord.getPaymentPrice().longValue())
                .totalSalesYesterday(yesterdayHtOrderRouteRecord.getPaymentPrice().longValue())
                .build();
    }

    public GetUserListResult userList(Long pageNo,Long pageSize){
        Page<MgUserInfo> userInfoPage = new Page<>();
        userInfoPage.setSize(pageSize);
        userInfoPage.setCurrent(pageNo);
        Page<MgUserInfo> htUserInfoPage = mgUserInfoDao.selectPage(userInfoPage, new LambdaQueryWrapper<MgUserInfo>()
                .eq(MgUserInfo::getDelFlag, 0));
        List<GetUserListResult.UserInfo> records = new ArrayList<>();
        htUserInfoPage.getRecords().forEach(mgUserInfo -> {
            GetUserListResult.UserInfo userInfo = GetUserListResult.UserInfo.builder().build();
            BeanUtil.copyProperties(mgUserInfo, userInfo);
            userInfo.setId(String.valueOf(mgUserInfo.getId()));
            userInfo.setRealName(mgUserInfo.getRealname());
            userInfo.setPermission(getPermission(String.valueOf(mgUserInfo.getId())));
            records.add(userInfo);
        });
        return GetUserListResult.builder()
                .total(htUserInfoPage.getTotal())
                .pageNum(htUserInfoPage.getCurrent())
                .pageSize(htUserInfoPage.getSize())
                .records(records)
                .build();
    }

    public String userEditPermissions(UpdateUserPerminssionsParam param){
        if(StringUtils.isBlank(param.getId())){
            throw new RuntimeException("主键不得为空");
        }
        String id = param.getId();
        //删除该用户的全部权限再新增
        mgUserPermissionDao.delete(new LambdaQueryWrapper<MgUserPermission>()
                .eq(MgUserPermission::getUsername, id));
        param.getPermissionIds().forEach(mgPerminssion ->{
            MgUserPermission mgUserPermission = new MgUserPermission();
            mgUserPermission.setUsername(id);
            mgUserPermission.setPermissionUrl(mgPerminssion);
            mgUserPermissionDao.insert(mgUserPermission);
        });
        return "修改权限成功!";
    }

    public String userEditInfo(UpdateUserInfoParam param){
        if(StringUtils.isBlank(param.getId())){
            throw new RuntimeException("主键不得为空");
        }
        if(StringUtils.isBlank(param.getUsername())){
            throw new RuntimeException("登录名不能为空");
        }
        if(StringUtils.isBlank(param.getRealName())){
            throw new RuntimeException("用户名不能为空");
        }
        if(StringUtils.isBlank(param.getPassword())){
            throw new RuntimeException("密码不能为空");
        }
        if(null == param.getStatus()){
            throw new RuntimeException("状态不能为空");
        }
        MgUserInfo mgUserInfo = mgUserInfoDao.selectById(param.getId());
        BeanUtil.copyProperties(param, mgUserInfo);
        mgUserInfo.setRealname(param.getRealName());
        mgUserInfo.setPassword(MD5Util.encode(param.getPassword(), mgUserInfo.getSalt()));
        return mgUserInfoDao.updateById(mgUserInfo) == 1 ? "修改成功!" : "修改失败!";
    }

    public String userAdd(InsertUserInfoParam param){
        if(StringUtils.isBlank(param.getUsername())){
            throw new RuntimeException("登录名不能为空");
        }
        if(StringUtils.isBlank(param.getRealName())){
            throw new RuntimeException("用户名不能为空");
        }
        if(StringUtils.isBlank(param.getPassword())){
            throw new RuntimeException("密码不能为空");
        }
        if(null == param.getStatus()){
            throw new RuntimeException("状态不能为空");
        }
        MgUserInfo mgUserInfo = new MgUserInfo();
        BeanUtil.copyProperties(param, mgUserInfo);
        mgUserInfo.setRealname(param.getRealName());
        mgUserInfo.setSalt(RandomUtil.createRandomStr(8));
        mgUserInfo.setPassword(MD5Util.encode(param.getPassword(), mgUserInfo.getSalt()));
        mgUserInfo.setDelFlag(0);
        return mgUserInfoDao.insert(mgUserInfo) == 1 ? "添加成功!" : "添加失败";
    }

    public String userDelete(RemoveUserInfoParam param){
        if(StringUtils.isBlank(param.getId())){
            throw new RuntimeException("主键不得为空");
        }
        MgUserInfo mgUserInfo = mgUserInfoDao.selectById(param.getId());
        mgUserInfo.setDelFlag(1);
        return mgUserInfoDao.updateById(mgUserInfo) == 1 ? "删除成功!" : "删除失败";
    }

    public List<GetPermissionInfo> permissions(){
        List<MgPerminssion> mgPerminssions = mgPerminssionDao.selectList(
                new LambdaQueryWrapper<MgPerminssion>().isNull(MgPerminssion::getParentId));
        List<GetPermissionInfo> getPermissionInfos = new ArrayList<>();
        mgPerminssions.forEach(mgPerminssion -> {
            GetPermissionInfo getPermissionInfo = GetPermissionInfo.builder()
                    .id(String.valueOf(mgPerminssion.getId()))
                    .name(mgPerminssion.getName())
                    .url(mgPerminssion.getUrl())
                    .build();
            getPermissionInfo.setSubs(getSubs(getPermissionInfo.getId()));
            getPermissionInfos.add(getPermissionInfo);
        });
        return getPermissionInfos;
    }

    /**
     * dfs路由菜单
     * @param id
     * @return
     */
    private List<GetPermissionInfo> getSubs(String id){
        List<MgPerminssion> mgPerminssions = mgPerminssionDao.selectList(
                new LambdaQueryWrapper<MgPerminssion>().eq(MgPerminssion::getParentId, id));
        if(CollectionUtils.isEmpty(mgPerminssions)){
            return null;
        }
        List<GetPermissionInfo> getPermissionInfos = new ArrayList<>();
        mgPerminssions.forEach(mgPerminssion -> {
            GetPermissionInfo getPermissionInfo = GetPermissionInfo.builder()
                    .id(String.valueOf(mgPerminssion.getId()))
                    .name(mgPerminssion.getName())
                    .url(mgPerminssion.getUrl())
                    .build();
            getPermissionInfo.setSubs(getSubs(getPermissionInfo.getId()));
            getPermissionInfos.add(getPermissionInfo);
        });
        return getPermissionInfos;
    }

    private List<String> getPermission(String Id){
        return mgUserPermissionDao.selectList(new LambdaQueryWrapper<MgUserPermission>()
                .eq(MgUserPermission::getUsername, Id)).stream().map(MgUserPermission::getPermissionUrl).collect(Collectors.toList());
    }

    /**
     * 获取Ip地址
     * @param request
     * @return
     */
    private static String getIpAdrress(HttpServletRequest request) {
        String Xip = request.getHeader("X-Real-IP");
        String XFor = request.getHeader("X-Forwarded-For");
        if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
            //多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = XFor.indexOf(",");
            if(index != -1){
                return XFor.substring(0,index);
            }else{
                return XFor;
            }
        }
        XFor = Xip;
        if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
            return XFor;
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getRemoteAddr();
        }
        return XFor;
    }
}
